package model;

import java.io.IOException;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;


public class Grizz implements Runnable {

    private boolean team;
    private int posX;
    private int posY;
    private int pontuacao;
    private int nMovimentos;
    private Animation sprite, up, down, left, right;
    private Image[] movementUp;
    private Image[] movementDown;
    private Image[] movementLeft;
    private Image[] movementRight;
    private static Semaphore sem, semSendB, semSendP;
    private static Semaphore semReadB, semReadP;
    private static int SLEEP = 200;
    public Grizz(boolean team, int posX, int posY) throws SlickException {
        this.team = team;
        this.posX = posX;
        this.posY = posY;
        this.pontuacao = 0;
        this.nMovimentos = 0;
        String path;
        if (team) {
            path = "whiteChar.png";
        } else {
            path = "blackChar.png";
        }

        movementUp = new Image[2];
        movementUp[0] = new Image(path);
        movementUp[1] = new Image(path);

        movementDown = new Image[2];
        movementDown[0] = new Image(path);
        movementDown[1] = new Image(path);

        movementLeft = new Image[2];
        movementLeft[0] = new Image(path);
        movementLeft[1] = new Image(path);

        movementRight = new Image[2];
        movementRight[0] = new Image(path);
        movementRight[1] = new Image(path);
        int[] duration = {1300, 300};

        up = new Animation(movementUp, duration, false);
        down = new Animation(movementDown, duration, false);
        left = new Animation(movementLeft, duration, false);
        right = new Animation(movementRight, duration, false);

        sprite = right;
        sem = new Semaphore(4);
        semSendB = new Semaphore(1);
        semSendP = new Semaphore(1);

        semReadB = new Semaphore(1);
        semReadP = new Semaphore(1);
    }

    public boolean isTeam() {
        return team;
    }

    public void setTeam(boolean team) {
        this.team = team;
    }

    public int getPontuacao() {
        return pontuacao;
    }

    public void setPontuacao(int pontuacao) {
        this.pontuacao = pontuacao;
    }

    public int getnMovimentos() {
        return nMovimentos;
    }

    public void setnMovimentos(int nMovimentos) {
        this.nMovimentos = nMovimentos;
    }

    public int getPosX() {
        return posX;
    }

    public void setPosX(int posX) {
        this.posX = posX;
    }

    public int getPosY() {
        return posY;
    }

    public void setPosY(int posY) {
        this.posY = posY;
    }

    public Image[] getMovementUp() {
        return movementUp;
    }

    public void setMovementUp(Image[] movementUp) {
        this.movementUp = movementUp;
    }

    public Image[] getMovementDown() {
        return movementDown;
    }

    public void setMovementDown(Image[] movementDown) {
        this.movementDown = movementDown;
    }

    public Image[] getMovementLeft() {
        return movementLeft;
    }

    public void setMovementLeft(Image[] movementLeft) {
        this.movementLeft = movementLeft;
    }

    public Image[] getMovementRight() {
        return movementRight;
    }

    public void setMovementRight(Image[] movementRight) {
        this.movementRight = movementRight;
    }

    public Animation getSprite() {
        return sprite;
    }

    public void setSprite(Animation sprite) {
        this.sprite = sprite;
    }

    public Animation getUp() {
        return up;
    }

    public void setUp(Animation up) {
        this.up = up;
    }

    public Animation getDown() {
        return down;
    }

    public void setDown(Animation down) {
        this.down = down;
    }

    public Animation getLeft() {
        return left;
    }

    public void setLeft(Animation left) {
        this.left = left;
    }

    public Animation getRight() {
        return right;
    }

    public void setRight(Animation right) {
        this.right = right;
    }

    @Override
    public synchronized void run() {

        if (team) {
            while (this.posY < 29) {
                try {
                    Thread.sleep(400);
                    sem.acquire();
                    Vertice dest = movimento();
                    if (dest != null) {
                        Mapa.getMapInfo()[this.posY][this.posX].setBlock(false);
                        this.posX = dest.getPosx();
                        this.posY = dest.getPosy();
                        Mapa.getMapInfo()[this.posY][this.posX].setBlock(true);
                    }
                    sem.release();
                } catch (InterruptedException ex) {
                    Logger.getLogger(Grizz.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } else {
            while (this.posY > 0) {
                try {
                    Thread.sleep(400);
                    sem.acquire();
                    Vertice dest = movimento();
                    if (dest != null) {
                        Mapa.getMapInfo()[this.posY][this.posX].setBlock(false);
                        this.posX = dest.getPosx();
                        this.posY = dest.getPosy();
                        Mapa.getMapInfo()[this.posY][this.posX].setBlock(true);
                        
                    }
                    sem.release();
                } catch (InterruptedException ex) {
                    Logger.getLogger(Grizz.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        if (team) {
            Mapa.setnBranco(Mapa.getnBranco() - 1);
        } else {
            Mapa.setnPreto(Mapa.getnPreto() - 1);
        }
        while (Mapa.getnPreto() != 0 || Mapa.getnBranco() != 0) {
            if (team) {

                if (readMessageB()) {
                    Vertice dest = livre();
                    this.posX = dest.getPosx();
                    this.posY = dest.getPosy();
                    Mapa.getMapInfo()[this.posY][this.posX].setBlock(true);
                }

            } else {

                if (readMessageP()) {
                    Vertice dest = livre();
                    this.posX = dest.getPosx();
                    this.posY = dest.getPosy();
                    Mapa.getMapInfo()[this.posY][this.posX].setBlock(true);
                }
            }
        }
    }

    private Vertice movimento() {
        Vertice at = Mapa.getMapInfo()[this.posY][this.posX];
        Vertice dest = null;
        int cont = 0;
        int pont = 0;
        if (team) {
            do {
                int i = (int) (Math.random() * at.getArestas().size());
                dest = at.getArestas().get(i).getDestino();
                pont = at.getArestas().get(i).getCusto();
                if (dest.getPosy() == 29 && dest.isBlock()) {
                    sendMessage(dest);
                    cont = 0;
                    break;
                }
                cont++;
            } while (dest.isBlock() || dest.getPosy() < at.getPosy() && cont < 4);
        } else {
            do {
                int i = (int) (Math.random() * at.getArestas().size());
                dest = at.getArestas().get(i).getDestino();
                cont++;
                pont = at.getArestas().get(i).getCusto();
                if (dest.getPosy() == 0 && dest.isBlock()) {
                    sendMessage(dest);
                    cont = 0;
                    break;
                }
            } while (dest.isBlock() || dest.getPosy() > at.getPosy() && cont < 4);
        }
        if (cont > 4) {
            do {
                int i = (int) (Math.random() * at.getArestas().size());
                dest = at.getArestas().get(i).getDestino();
                pont = at.getArestas().get(i).getCusto();
                cont++;
            } while (dest.isBlock());
        }
//        Vertice dest = null;
//        double distAnt = 1000000000;
//        double dist;
//        if (team) {
//            for (Aresta aresta : at.getArestas()) {
//                dist = aresta.getDestino().distanciaManhattan(new Vertice(posX));
//                if (dist <= distAnt && !aresta.getDestino().isBlock()) {
//                    dest = aresta.getDestino();
//                    distAnt = dist;
//                }
//            }
//        } else {
//            for (Aresta aresta : at.getArestas()) {
//                dist = aresta.getDestino().distanciaManhattan(new Vertice(Mapa.getWIDTH()*this.posY+this.posX));
//                if (dist <= distAnt && !aresta.getDestino().isBlock()) {
//                    dest = aresta.getDestino();
//                    distAnt = dist;
//                }
//            }

//            if (Thread.currentThread().getId() == 56) {
//                System.out.println(at.getPosx() + "->" + dest.getPosx());
//                System.out.println(at.getPosy() + "->" + dest.getPosy());
//            }
        if (team) {
            Mapa.setPBranco(Mapa.getPBranco() - pont);

        } else {
            Mapa.setPPreto(Mapa.getPPreto() - pont);

        }
        return dest;
    }

    private boolean readMessageP() {
        try {
            semReadP.acquire();
            if (Mapa.getPreto() != null) {
                if ((Mapa.getPreto().getPosx() == this.posX && Mapa.getPreto().getPosy() == this.posY)) {
                    Mapa.setPreto(null);
                    semSendP.release();
                    semReadP.release();
                    return true;
                }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Grizz.class.getName()).log(Level.SEVERE, null, ex);
        }
        semReadP.release();
        return false;
    }

    private boolean readMessageB() {
        try {
            semReadB.acquire();
            if (Mapa.getBranco() != null) {
                if ((Mapa.getBranco().getPosx() == this.posX && Mapa.getBranco().getPosy() == this.posY)) {
                    Mapa.setBranco(null);
                    semSendB.release();
                    semReadB.release();
                    return true;
                }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Grizz.class.getName()).log(Level.SEVERE, null, ex);
        }
        semReadB.release();
        return false;
    }

    private void sendMessage(Vertice dest) {
        if (team) {
            try {
                semSendB.acquire();
                Mapa.setBranco(new Mensagem(dest.getPosx(), dest.getPosy()));
            } catch (InterruptedException ex) {
                Logger.getLogger(Grizz.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            try {
                semSendP.acquire();
                Mapa.setPreto(new Mensagem(dest.getPosx(), dest.getPosy()));
            } catch (InterruptedException ex) {
                Logger.getLogger(Grizz.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

    }

//    private Vertice espaco() {
//        if (livre()) {
//            if (Mapa.getMapInfo()[this.posY][this.posX - 1].isBlock()) {
//                sendMessage(Mapa.getMapInfo()[this.posY][this.posX - 1]);
//            }
//            if (!team) {
//                System.out.println("X -> " + (this.posX - 1) + " Y -> " + this.posY);
//            }
//            return Mapa.getMapInfo()[this.posY][this.posX - 1];
//        } else {
//            if (Mapa.getMapInfo()[this.posY][this.posX + 1].isBlock()) {
//                sendMessage(Mapa.getMapInfo()[this.posY][this.posX + 1]);
//            }
//            System.out.println("X -> " + (this.posX + 1) + " Y -> " + this.posY);
//            return Mapa.getMapInfo()[this.posY][this.posX + 1];
//        }
//    }
    private Vertice livre() {
        int i = 1;
        while (true) {
            if (this.getPosX() - i >= 0 && !Mapa.getMapInfo()[this.getPosY()][this.getPosX() - i].isBlock()) {
                Mapa.getMapInfo()[this.getPosY()][this.getPosX() - i].setBlock(true);
                return Mapa.getMapInfo()[this.getPosY()][this.getPosX() - i];
            }
            if (this.getPosX() + i <= 39 && !Mapa.getMapInfo()[this.getPosY()][this.getPosX() + i].isBlock()) {
                Mapa.getMapInfo()[this.getPosY()][this.getPosX() + i].setBlock(true);
                return Mapa.getMapInfo()[this.getPosY()][this.getPosX() + i];
            }
            i++;
        }
    }
}
//    private boolean livre() {
//        for (int i = this.getPosX()-1; i > 0; i--) {
//            if (!Mapa.getMapInfo()[this.getPosY()][i].isBlock()) {
//                return true;
//            }
//        }
//        return false;
//    }
//}
